#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace Camera_2DComponent
{
    #region Object_2D
    public class Object_2D : IComparable<Object_2D>
    {
        /* Controls the order things get drawn in.  Starts with the farthest away from the user
         * and draws up through the closets to the user
         * Because of the way the sort works (not guaranteed to keep order if items are =), if items will
         * be drawn on each other (a menuitem on a menu background, for instance) they need a new enum.
         * Z_BACKGROUND - the background layer.  Tile engine, etc.
         * Z_UNDERGROUND - Anything that would look "underground".
         * Z_NORMAL - Pretty much all objects on screen.
         * Z_FLYING - Anything that would be considered above most objects, like clouds, air creeps, etc.
         * Z_INTERFACE - The main interface elements for the game. 
         * Z_INTERFACEITEM - An item on the interface.  A button to push, etc.
         * Z_MENU - The menu
         * Z_MENUITEM - An item on the menu
         */
        public enum ZORDER_ENUM {Z_BACKGROUND, Z_UNDERGROUND, Z_NORMAL, Z_FLYING, 
            Z_INTERFACE, Z_INTERFACEITEM, Z_MENU, Z_MENUITEM};

        protected Texture2D _texture= null;
        protected Texture2D _selectedTexture=null;
        protected Texture2D _currentTexture=null;

        protected int _frameNumber;  // What's my current animation frame?
        protected int _updatesPerFrame; //How many game updates till I draw my next frame?

        protected Vector2 _loc; // Where in the world am I?
        public Vector2 Loc
        {
            get { return this._loc; }
        }

        protected bool _selected = false;   // Has we been selected by the mouse?
        public bool Selected
        {
            get { return this._selected; }
            set
            {
                this._selected = value;
                UpdateSelection(value);
            }
        }

        protected bool _hovered = false;   // Has we been hovered over by the mouse?
        public bool Hovered
        {
            get { return this._hovered; }
            set
            {
                this._hovered = value;
                UpdateHover(value);
            }
        }

        protected ZORDER_ENUM _zorder;
        public ZORDER_ENUM Zorder
        {
            get { return this._zorder; }
        }

        protected bool _scalable = true;  // Can this object be scaled with the map?  Or is it interface?
        public bool Scalable
        {
            get { return this._scalable; }
        }

        protected int _Xsize;  // How big is this object x wise?
        public int Xsize
        {
            get { return this._Xsize; }
        }

        protected int _Ysize; // How tall is this object y wise.  As opposed to tall x wise objects...
        public int Ysize
        {
            get { return this._Ysize; }
        }
        protected string _name = null;  // The name of the object.
        public string name 
        {
            get {return this._name;}
        }
        #region Object 2D Constructors
        public Object_2D(int MyXSize, int MyYSize) 
        {
            this._frameNumber = 0;
            this._updatesPerFrame = 1;
            this._Xsize = MyXSize;
            this._Ysize = MyYSize;
        }
        public Object_2D(string Name, Vector2 Loc, Texture2D DisplayTexture, int MyXSize, int MyYSize)
        {
            this._frameNumber = 0;
            this._updatesPerFrame = 1;
            this._loc = Loc;
            this._texture = DisplayTexture;
            this._selectedTexture = null;
            this._currentTexture = this._texture;
            this._name = Name;
            this._Xsize = MyXSize;
            this._Ysize = MyYSize;
        }
        public Object_2D(string Name, Vector2 Loc, Texture2D DisplayTexture, Texture2D SelectedTexture, int MyXSize, int MyYSize)
        {
            this._frameNumber = 0;
            this._updatesPerFrame = 1;
            this._loc = Loc;
            this._texture = DisplayTexture;
            this._selectedTexture = SelectedTexture;
            this._currentTexture = this._texture;
            this._name = Name;
            this._Xsize = MyXSize;
            this._Ysize = MyYSize;
        }
        #endregion

        public virtual void Draw(SpriteBatch renderer)
        {
            renderer.Draw(_currentTexture, _loc, Color.White);
        }

        public virtual void Update()
        {
            //Apply AI here
            // Movement\Pathing
            //Adjust animation frames
        }

        public int CompareTo(Object_2D temp)
        {
            //Object_2D temp = (Object_2D)obj;
            if (this._zorder > temp._zorder)
            {
                return 1;
            }
            else
            {
                if (temp._zorder == this._zorder)
                    return 0;
                else
                    return -1;
            }
        }

        private void UpdateHover(bool Value)
        {
            if (_selectedTexture == null)
                return;

            if (Value)
            {
                this._currentTexture = this._selectedTexture;
            }
            else
            {
                this._currentTexture = this._texture;
            }
        }

        private void UpdateSelection(bool Value)
        {
            if (_selectedTexture == null)
            {
                if (Value)
                {
                    OnSelect();
                }
                return;
            }

            if (Value)
            {
                this._currentTexture = this._selectedTexture;
                OnSelect();
            }
            else
            {
                this._currentTexture = this._texture;
            }
        }

        public virtual void OnSelect()
        {
        }

    }

    #endregion

    public class Camera_2D : Microsoft.Xna.Framework.DrawableGameComponent
    {
        public List<Object_2D> ActiveObjects;
        private Vector2 _cameraPosition;
        private SpriteBatch _spriteBatch;

        public Camera_2D(Game game)
            : base(game)
        {
            this.ActiveObjects = new List<Object_2D>();
            // TODO: Construct any child components here
        }


        private Vector2 _worldPosition;


        public Vector2 CameraPosition
        {
            get { return _cameraPosition; }
            set { _cameraPosition = value; }
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            _cameraPosition = new Vector2(0, 0);
            
            this.Enabled = true;
            this.Visible = false;
            base.Initialize();
        }


        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime GameTime)
        {
            // TODO: Add your update code here
            for (int i = 0; i < ActiveObjects.Count; i++)
            {
                ActiveObjects[i].Update();
            }
            base.Update(GameTime);
        }
        public override void Draw(GameTime Gametime)
        {
            // TODO: Loop through the list of objects on our screen and 
            // apply them/draw them.

            _spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
            for (int i = 0; i < ActiveObjects.Count; i++)
            {
                ActiveObjects[i].Draw(_spriteBatch);
            }
            // get the screen position of the node
            //Vector2 drawPosition = ApplyTransformations(node.Position);
            //node.Draw(spriteRenderer, drawPosition);
            _spriteBatch.End();
        }
        private Vector2 ApplyTransformations(Vector2 NodePosition)
        {
            // apply translation
            // Basically, if the object is in the camera's view
            // need to figure out where on the screen it is then...
            Vector2 finalPosition = NodePosition - _cameraPosition;
            // you can apply scaling and rotation here also
            //.....
            //--------------------------------------------
            return finalPosition;
        }
        public void Translate(Vector2 MoveVector)
        {
            _cameraPosition += MoveVector;
        }

        protected override void LoadGraphicsContent(bool LoadAllContent)
        {
            if (LoadAllContent)
            {
                _spriteBatch = new SpriteBatch(GraphicsDevice);
            }
        }



    }
}


